package com.javalsj.common.web.filter;

import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.GenericFilterBean;

import com.javalsj.common.base.consts.CommonConst;
import com.javalsj.common.base.util.UUIDUtils;

/**
 * @description 从请求头获取上下文变量过滤器
 * @author WANGJIHONG
 * @date 2019年5月22日 上午10:54:00
 * @Copyright 版权所有 (c) www.javalsj.com
 * @memo 无备注说明
 */
@Component
public class BusinessContextDataFilter extends GenericFilterBean {

	private static final Logger LOGGER = LoggerFactory.getLogger(BusinessContextDataFilter.class);

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		HttpServletRequest req = (HttpServletRequest) request;
		
		BusinessContextData ttlContextData = new BusinessContextData();
		// 添加服务器IP信息
		ttlContextData.setServerIp(getServerIp(req));
		// 添加客户端IP信息
		ttlContextData.setClientIp(getClientIp(req));
		// 添加系统内部全链路追踪ID上下文信息
		ttlContextData.setTraceId(getTraceId(req));
		// 添加请求头信息
		ttlContextData.setRequestHeaders(getRequestHeaders(req));
		// 添加请求参数信息
		ttlContextData.setRequestParams(getRequestParams(req));

		BusinessContext.setTtlContext(ttlContextData);
		
		chain.doFilter(request, response);
	}

	private Map<String, String> getRequestParams(HttpServletRequest request) {
		Map<String, String> paramsMap = new HashMap<>();
		Enumeration<String> bodyNames = request.getParameterNames();
		if (bodyNames != null) {
			while (bodyNames.hasMoreElements()) {
				String name = bodyNames.nextElement();
				String values = request.getParameter(name);
				paramsMap.put(name, values);
			}
		}
		return paramsMap;
	}

	private Map<String, String> getRequestHeaders(HttpServletRequest request) {
		Map<String, String> headerMap = new HashMap<>();
		Enumeration<String> headerNames = request.getHeaderNames();
		if (headerNames != null) {
			while (headerNames.hasMoreElements()) {
				String name = headerNames.nextElement();
				String values = request.getHeader(name);
				headerMap.put(name, values);
			}
		}
		return headerMap;
	}

	private UUID getTraceId(HttpServletRequest req) {
		String traceIdStr = req.getHeader(CommonConst.HttpHeaderConst.X_TRACE_ID);
		UUID traceId;
		if (StringUtils.isEmpty(traceIdStr)) {
			traceId = UUIDUtils.newUUID();
		} else {
			traceId = UUIDUtils.fromString(traceIdStr);
			if (traceId == null) {
				LOGGER.error("请求[{}]未传递正确的全链路追踪ID[{}]。", req.getPathInfo(), traceIdStr);
			}
		}
		return traceId;
	}

	private String getClientIp(HttpServletRequest req) {
		String clientIp = req.getHeader(CommonConst.HttpHeaderConst.X_Client_IP);
		if (StringUtils.isEmpty(clientIp)) {
			clientIp = req.getHeader("x-forwarded-for");
			if (clientIp == null || clientIp.length() == 0 || "unknown".equalsIgnoreCase(clientIp)) {
				clientIp = req.getHeader("Proxy-Client-IP");
			}
			if (clientIp == null || clientIp.length() == 0 || "unknown".equalsIgnoreCase(clientIp)) {
				clientIp = req.getHeader("WL-Proxy-Client-IP");
			}
			if (clientIp == null || clientIp.length() == 0 || "unknown".equalsIgnoreCase(clientIp)) {
				clientIp = req.getRemoteAddr();
			}
		}
		return clientIp;
	}

	private String getServerIp(HttpServletRequest req) {
		InetAddress inetAddress;
		try {
			inetAddress = InetAddress.getLocalHost();
		} catch (UnknownHostException e) {
			return "localhost";
		}
		return inetAddress.getHostAddress();
	}

}
